<?php

namespace app\common\logic;

use app\api\service\ApiPayment;
use app\common\library\enum\CodeEnum;
use app\common\library\enum\BalanceCashEnum;
use think\Db;
use think\Log;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;

class BalanceCash extends BaseLogic
{
    /**
     * 获取订单信息.
     *
     *
     * @param array       $where
     * @param bool|string $field
     *
     * @return mixed
     */
    public function getOrderCashInfo($where = [], $field = 'a.*,u.account,b.name as method')
    {
        $this->modelBalanceCash->alias('a');

        $join = [
            ['user_account u', 'a.account = u.id', 'left'],
            ['banker b', 'u.bank_id = b.id', 'left'],
        ];

        $this->modelBalanceCash->join = $join;

        return $this->modelBalanceCash->getInfo($where, $field);
    }

    /**
     * 获取打款列表.
     *
     *
     * @param array  $where
     * @param string $field
     * @param string $order
     * @param int    $paginate
     *
     * @return mixed
     */
    public function getOrderCashList($where = [], $field = 'a.*,u.account,b.name as method', $order = 'a.create_time desc', $paginate = 15)
    {
        $this->modelBalanceCash->alias('a');

        $join = [
            ['user_account u', 'a.account = u.id', 'left'],
            ['banker b', 'u.bank_id = b.id', 'left'],
        ];

        $this->modelBalanceCash->join = $join;

        return $this->modelBalanceCash->getList($where, $field, $order, $paginate);
    }

    /**
     * 获取打款列表总数.
     *
     *
     * @param array $where
     *
     * @return mixed
     */
    public function getOrderCashCount($where = [])
    {
        return $this->modelBalanceCash->getCount($where);
    }

    /**
     * 新增提现申请记录.
     *
     *
     * @param $data
     *
     * @return array
     */
    public function saveUserCashApply($data)
    {
        //TODO 数据验证
        $validate = $this->validateBalance->check($data);

        if (!$validate) {
            return ['code' => CodeEnum::ERROR, 'msg' => $this->validateBalance->getError()];
        }
        //TODO 添加数据
        Db::startTrans();
        try {
            $data['cash_no'] = create_order_no();
            //提现
            $this->modelBalanceCash->setInfo($data);
            //资金变动 - 资金记录
            $this->logicBalanceChange->creatBalanceChange($data['uid'], $data['amount'], '提现扣减可用金额', 'enable', true);

            Db::commit();

            action_log('新增', '个人提交提现申请'.$data['remarks']);

            return ['code' => CodeEnum::SUCCESS, 'msg' => '新增提现申请成功'];
        } catch (\Exception $ex) {
            Log::error('新增提现申请出现错误 : '.$ex->getMessage());
            Db::rollback();

            return ['code' => CodeEnum::ERROR, 'msg' => config('app_debug') ? $ex->getMessage()
                : '新增提现申请出现错误', ];
        }
    }

    /**
     * 推送打款队列.
     *
     *
     * @param array $where
     *
     * @return array
     */
    public function pushBalanceCash($where = [])
    {
        //订单
        $order = $this->getOrderCashInfo($where);
        Db::startTrans();
        try {
            $this->modelBalanceCash->setFieldValue(['id' => $order['id']], 'status', BalanceCashEnum::Approve);

            Db::commit();

            action_log('审核', '提现申请，单号：'.$order['cash_no']);

            return  ['code' => CodeEnum::SUCCESS, 'msg' => '已经确认'];
        } catch (\Exception $ex) {
            Log::error('审核提现申请出现错误 : '.$ex->getMessage());
            Db::rollback();

            return ['code' => CodeEnum::ERROR, 'msg' => config('app_debug') ? $ex->getMessage() : '审核异常'];
        }
    }

    /**
     * 驳回提现.
     *
     *
     * @param array $where
     *
     * @return array
     */
    public function rebutBalanceCash($where = [])
    {
        //订单
        $order = $this->getOrderCashInfo($where);
        if (1 != $order['status']) {
            return ['code' => CodeEnum::SUCCESS, 'msg' => '已经操作过了'];
        }
        Db::startTrans();
        try {
            $this->modelBalanceCash->setFieldValue(['id' => $order['id']], 'status', BalanceCashEnum::Reject);

            //资金变动 - 资金记录
            $this->logicBalanceChange->creatBalanceChange($order['uid'], bcadd($order['amount'], $order['fee'], 2), '提现驳回', 'enable', false);

            Db::commit();

            action_log('驳回', '提现申请，单号：'.$order['cash_no']);

            return  ['code' => CodeEnum::SUCCESS, 'msg' => '已经驳回'];
        } catch (\Exception $ex) {
            Log::error('驳回提现申请出现错误 : '.$ex->getMessage());
            Db::rollback();

            return ['code' => CodeEnum::ERROR, 'msg' => config('app_debug') ? $ex->getMessage() : '驳回异常'];
        }
    }

    /**
     * 设置某个字段参数.
     *
     *
     * @param array  $where
     * @param string $field
     * @param string $value
     */
    public function setCashValue($where = [], $field = 'cash_no', $value = '')
    {
        $this->modelBalanceCash->setFieldValue($where, $field, $value);
    }

    public function saveUserCashApplyBatch($filePath = '', $remark = '')
    {
        Db::startTrans();
        try {
            $uid = is_login();
            $spreadsheet = IOFactory::load($filePath); // 载入Excel表格
            $worksheet = $spreadsheet->getActiveSheet();

            $highestRow = $worksheet->getHighestRow(); // 总行数
            if ($highestRow < 2) {
                return [0, 'Excel文件中没有需要处理的数据。'];
            }

            $highestColumn = $worksheet->getHighestColumn(); // 总列数
            $highestColumnIndex = Coordinate::columnIndexFromString($highestColumn);
            if ($highestColumnIndex < 3) {
                return [0, 'Excel文件中数据格式不正确，请使用提供的文件模板。'];
            }

            $feePreData = 3; //每笔提现费用，3元；

            $allGoodDataList = [];
            $allowAmountList = [100, 200, 500, 1000, 5000, 10000, 20000];
            for ($row = 2; $row <= $highestRow; ++$row) { // 从第二行开始
                $item = [];
                $goodRow = true;
                for ($column = 1; $column <= $highestColumnIndex; ++$column) {
                    $item[] = $worksheet->getCellByColumnAndRow($column, $row)->getValue();
                    if (null == $item[$column - 1] || '' == $item[$column - 1]) {
                        // $goodRow = false;
                        unset($item[$column - 1]);
                        break;
                    }
                }

                if ($goodRow) {
                    if (!in_array($item[2], $allowAmountList)) {
                        // return [0, '第'.$row.'行的金额数据错误，仅支持如下转账金额：<br/>100，200，500，1000，5000，10000，20000。'];
                    }

                    $rateFee = bcmul($item[2], 0.0055, 2);
                    $fee = bcadd($feePreData, $rateFee, 2);
                    $extra = array_slice($item, 3);
                    $allGoodDataList[] = [
                        'name' => $item[0],
                        'bank' => $item[1],
                        'amount' => $item[2],
                        'fee' => $fee,
                        'extra' => $extra ? json_encode($extra) : '',
                    ];
                }
            }

            $goodDataCount = sizeof($allGoodDataList);
            if ($goodDataCount <= 0) {
                return [0, 'Excel文件中没有需要处理的数据。'];
            }

            $totalamount = 0;
            foreach ($allGoodDataList as $item) {
                $totalamount = bcadd($totalamount, $item['amount'], 2) + $item['fee'];
            }

            $user = (new \app\common\model\Balance())->getUserBalance(['uid' => $uid]);
            if (!is_null($user) && $user['enable'] < $totalamount) {
                return [0, '批量提现提交失败, 可用资金不足！'];
            }

            $userInfo = (new \app\common\model\User())->getUser($uid);
            $balanceCashStatus = BalanceCashEnum::Submit;
            if ($userInfo && 1 != $userInfo->cash_approve) {
                $balanceCashStatus = BalanceCashEnum::Approve;
            }
            foreach ($allGoodDataList as $item) {
                $extra = array_slice($item, 4);
                $cashList[] = [
                    'uid' => $uid,
                    'cash_no' => create_general_no(),
                    'bank_account_name' => $item['name'],
                    'bank_account' => $item['bank'],
                    'amount' => $item['amount'],
                    'fee' => $item['fee'],
                    'status' => $balanceCashStatus,
                    'remarks' => $remark,
                    'cnl_id' => $userInfo['cash_channel'],
                    'extra' => $item['extra']
                ];
            }
            $this->modelBalanceCash->saveAll($cashList);

            if ($this->logicBalanceChange->creatBalanceChange($uid, $totalamount, '批量提现', 'enable', true)) {
                Db::commit();

                action_log('提现', '批量提现申请');

                return [1, '批量提现申请成功, 总共'.$goodDataCount.'条记录等待处理！'];
            } else {
                Db::rollback();

                return [0, '批量提现申请失败, 扣除资金失败！'];
            }
        } catch (\Exception $ex) {
            //记录日志
            Log::error("批量提现申请出现错误:[{$ex->getMessage()}]");
            Db::rollback();

            //抛出错误异常
            return [CodeEnum::ERROR,  config('app_debug') ? $ex->getMessage() : '批量提现申请出现错误'];
        }
    }

    /**
     * 轮训待支付接口并调用渠道接口下单.
     *
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function checkApproveOrderTask()
    {
        $list = $this->modelBalanceCash->where('status', BalanceCashEnum::Approve)
            ->limit(10)
            ->order('id', 'desc')
            ->select();
        foreach ($list as $item) {
            $channel = $this->logicPay->getChannelInfo(['id' => $item->data['cnl_id']], 'action');
            $methodName = $channel ? 'doWithdraw'.$channel['action'] : 'doWithdrawFuioupay';

            return $this->$methodName($item->data);
        }
    }

    /**
     * 轮训Fastpay已下单接口.
     */
    public function checkFastPayAppliyOrderTask()
    {
        $channel = $this->logicPay->getChannelInfo(['action' => 'Fastpay'], 'id');
        $accountInfo = $this->logicPay->getAccountInfo(['cnl_id' => $channel['id']]);
        $config = json_decode($accountInfo['param'], true);
        $fastpayInstance = ApiPayment::Fastpay($config);

        $list = $this->modelBalanceCash->where(['status' => BalanceCashEnum::PayAppliy, 'cnl_id' => $channel['id']])
            ->limit(10)
            ->order('id', 'desc')
            ->select();
        foreach ($list as $item) {
            $result = $fastpayInstance->orderQuery($item['id']);
            if ($result && $result['retcode'] = '0000') {
                switch ($result['result']) {
                    case '1':
                        $this->finishOrder($item['id']);
                        break;
                    case '2':   //处理中
                        break;
                    case '3':   //支付失败
                    case '4':   //处理中
                        //退款
                        $this->cancelOrder($item['id']);
                        break;
                }
            }
        }
    }

    /**
     * 提现: Fastpay.
     */
    public function doWithdrawFastpay($data)
    {
        $accountInfo = $this->logicPay->getAccountInfo(['cnl_id' => $data['cnl_id']]);
        $config = json_decode($accountInfo['param'], true);
        // pay($tradeNo, $name, $bank, $amount, $bankCode, $idcardNo, $mobile, $channelCode)
        $extra = json_decode($data['extra'], true);
        $bankCode = "";
        $idcardNo = "";
        $mobile = "";
        if (is_array($extra)) {
            if (isset($extra[0])) {
                $bankCode = $extra[0];
            }
            
            if (isset($extra[1])) {
                $idcardNo = $extra[1];
            }

            if (isset($extra[2])) {
                $mobile = $extra[2];
            }
        }
        
        $result = ApiPayment::Fastpay($config)->pay($data['id'], $data['bank_account_name'], $data['bank_account'], $data['amount'], $bankCode, $idcardNo, $mobile);
        if ($result && '0000' == $result['ret_code']) {
            $this->modelBalanceCash->update(['id' => $data['id'], 'status' => BalanceCashEnum::PayAppliy]);
        }
    }

    /**
     * 提现: Fuiou.
     */
    public function doWithdrawFuioupay($data)
    {
        $orderno = str_pad($data['id'], 10, '0', STR_PAD_LEFT); //填充至至少10个字符
        $result = $this->doWithdrawRequest($data['bank_account'], $data['bank_account_name'], $data['amount'], $orderno, date('Ymd', $data['create_time']));
        if ($result && '000000' == $result->ret) {
            $this->modelBalanceCash->update(['id' => $data['id'], 'status' => BalanceCashEnum::PayAppliy]);
        }
    }

    /**
     * 提现.
     *
     * @param string(30)     $accntno  账号
     * @param string(10, 28) $accntnm  账号名称
     * @param float(10, 2)   $amt      金额(单位: 元)
     * @param string         $orderno  订单号
     * @param string         $merdt    订单日期
     * @param string         $cityno   城市代码
     * @param string         $bankno   总行代码
     * @param string         $branchnm 支行代码
     * @param string         $mobile   手机号
     * @param string         $memo     备注
     * @param string         $entseq   企业流水号
     */
    public function doWithdrawRequest($accntno, $accntnm, $amt, $orderno = '', $merdt = '', $cityno = '', $bankno = '', $branchnm = '', $mobile = '', $memo = '', $entseq = '')
    {
        //生成交易记录

//        $mchntcd = "0002900F0345178";
//        $mchntcd = "0002900F0345179";
//        $mchntkey = "123456";

        $mchntcd = config('code.fuiou')['cd'];
        $mchntkey = config('code.fuiou')['key'];
        $apiUrl = config('code.fuiou')['apiUrl'];

        $amt = $amt * 100;
        $ver = '1.00';
        $reqtype = 'payforreq';

        $xml = "<?xml version='1.0' encoding='utf-8' standalone='yes'?><payforreq><ver>".$ver.'</ver><merdt>'.$merdt.'</merdt><orderno>'.$orderno.'</orderno><bankno>'.$bankno.'</bankno><cityno>'.$cityno.'</cityno><accntno>'.$accntno.'</accntno><accntnm>'.$accntnm.'</accntnm><branchnm>'.$branchnm.'</branchnm><amt>'.$amt.'</amt><mobile>'.$mobile.'</mobile><entseq>'.$entseq.'</entseq><memo>'.$memo.'</memo></payforreq>';

        $macsource = $mchntcd.'|'.$mchntkey.'|'.$reqtype.'|'.$xml;
        $mac = md5($macsource);
        $mac = strtoupper($mac);
        $list = array('merid' => $mchntcd, 'reqtype' => $reqtype, 'xml' => $xml, 'mac' => $mac);
        $query = http_build_query($list);
        $options = array(
            'http' => array(
                'header' => "Content-Type: application/x-www-form-urlencoded\r\n".
                    'Content-Length: '.strlen($query)."\r\n".
                    "User-Agent:MyAgent/1.0\r\n",
                'method' => 'POST',
                'content' => $query,
            ),
        );
        $context = stream_context_create($options);
        $result = file_get_contents($apiUrl, false, $context, 0, 40000);

        try {
            return simplexml_load_string($result);
        } catch (\Exception $e) {
            return false;
        }
    }

    /**
     * 完成订单.
     *
     * @param $id
     *
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function finishOrder($id)
    {
        $order = $this->modelBalanceCash->where('id', $id)->find();
        if (BalanceCashEnum::PayAppliy == $order['status']) {
            $this->modelBalanceCash->update(['id' => $order['id'], 'status' => BalanceCashEnum::PayDone]);

            return true;
        }

        if (BalanceCashEnum::PayDone == $order['status']) {
            return true;
        }

        return false;
    }

    /**
     * 取消订单
     */
    public function cancelOrder($id)
    {
        //订单
        $order = $this->modelBalanceCash->getInfo(['id' => $id]);
        if (BalanceCashEnum::PayAppliy == $order['status']) {
            Db::startTrans();
            try {
                $this->modelBalanceCash->setFieldValue(['id' => $id], 'status', BalanceCashEnum::PayReject);

                //资金变动 - 资金记录
                $this->logicBalanceChange->creatBalanceChange($order['uid'], bcadd($order['amount'], $order['fee'], 2), '支付失败', 'enable', false);

                Db::commit();

                action_log('支付失败', '提现申请，单号：'.$order['cash_no']);

                return  ['code' => CodeEnum::SUCCESS, 'msg' => '已经驳回'];
            } catch (\Exception $ex) {
                Log::error('支付失败出现错误 : '.$ex->getMessage());
                Db::rollback();

                return ['code' => CodeEnum::ERROR, 'msg' => config('app_debug') ? $ex->getMessage() : '支付失败异常'];
            }
        }
    }
}
